home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / mskrmsrc.zip / MSSFIL.ASM < prev    next >
Assembly Source File  |  1991-10-24  |  64KB  |  1,839 lines

  1.     NAME    mssfil
  2. ; File MSSFIL.ASM
  3.     include mssdef.h
  4. ;       Copyright (C) 1982,1991, Trustees of Columbia University in the
  5. ;       City of New York.  Permission is granted to any individual or
  6. ;       institution to use, copy, or redistribute this software as long as
  7. ;       it is not sold for profit and this copyright notice is retained.
  8. ; Edit history:
  9. ; 6 Sept 1991 version 3.11
  10. ; 2 March 1991 version 3.10
  11. ; Last edit 6 Sept 1991
  12.  
  13.     public    buff, gofil, ptchr, gtchr, getfil, gtnfil, doenc, dodec
  14.     public    encbuf, decbuf, diskio, auxfile, fparse, prtasz, prtscr
  15.     public    strlen, strcat, strcpy, tfilsz, templp, latin1, charids
  16.     public    L1cp437, L1cp850, L1cp860, L1cp863, L1cp865, unique
  17.     public    load, cplatin, goopen
  18.  
  19. data    segment
  20.     extrn    flags:byte, trans:byte, denyflg:word, dosnum:word
  21.     extrn    oldkbt:word, oldper:word, filtst:byte, rdbuf:byte, fsta:byte
  22.     extrn    curdsk:byte
  23.  
  24. ermes4  db    'Unable to make unique name',0
  25. ermes9    db    'Printer not ready',0
  26. erms12    db    'Unable to create file ',0
  27. erms13    db    'Error writing output file',0
  28. infms5  db    'Renaming file to $'
  29. infms6    db    cr,lf,'?Unable to open file$'
  30. asmsg    db    ' as $'
  31. crlf    db    cr,lf,'$'
  32. printer    db    'PRN',0
  33. screen    db    'CON',0
  34. loadhlp    db    'filename$'
  35.                 ; DOS special chars allowed in filenames
  36. spchar2    db    '$', 26h, 23h, 40h, 21h, 25h, 27H, '(', ')', '-', 7bh, 7dh
  37.     db    5fh, 5eh, 7eh, 60h
  38. spc2len    equ    $-spchar2
  39.  
  40. textctl    db    cr,lf,tab,bell,ff,ctlz    ; controls allowed in text files
  41. textctlen equ    $-textctl
  42.     even
  43. filflg    db    0        ; input buffer has data, if non-zero
  44. tmprptq    db    0        ; working copy of repeat prefix
  45. rptval    db    0        ; repeated character
  46. rptct    db    1        ; number of times it's repeated
  47. decoutp    dw    0        ; ptr to proc to dump decode output buffer
  48. encinp    dw    0        ; ptr to proc to refill encode input buffer
  49. dchrcnt dw    0        ; number of chars in the decode file buffer
  50. echrcnt dw    0        ; number of chars in the encode file buffer
  51. dbufpnt dw    0        ; position in file buffer, decoder
  52. ebufpnt dw    0        ; position in file buffer, encoder
  53. decbuf    db    512 dup (0)    ; decoding source buffer
  54.     db    0        ; safety for possible null terminator
  55. encbuf    db    512 dup (0)    ; encoding source buffer
  56.     db    0        ; safety for possible null terminator
  57.  
  58. tfilsz    dw    0,0        ; bytes transferred (double word qty)
  59. nmoflg    db    0        ; have override filename, if non-zero
  60. templp    db    65 dup (?)    ; temp for local path part
  61. templf    db    14 dup (?)    ; temp for local filename part
  62. temprp    db    65 dup (?)    ; temp for remote path part
  63. temprf    db    14 dup (?)    ; temp for remote filename part
  64. auxfile    db    65 dup (?)    ; auxillary filename for general use
  65. diskio    filest    <>        ; ditto, for ordinary file transfers
  66. buff    db    buffsz dup (?)    ; use as our Disk Transfer Area
  67. havdot    db    0        ; dot-found status in verify
  68. unum    dw    0        ; unique filename generation number
  69. temp    dw    0
  70.                 ; charids: table of transfer char-set idents
  71. charids dw    3        ; qty, pointers to char set idents
  72.     dw    chtrans,chlatin1,chcyrill
  73. chtrans    db    1,'A'        ; Transparent: char count, ident
  74. chlatin1 db    6,'I6/100'    ; Latin1: char count, ident
  75. chcyrill db    6,'I6/144'    ; Cyrillic: char count, ident
  76.                 ; end of charids info
  77. loadtab    db    1        ; LOAD command table
  78.     mkeyw    'Transfer-character-set',0
  79.  
  80. filtab    macro
  81.     cnt = 128
  82.     rept    128            ; 128 idenity entries
  83.     db    cnt            ; initialize table to 128 .. 255
  84.     cnt = cnt + 1
  85.     endm
  86. endm
  87.  
  88. userin    equ    this byte        ; LOAD command
  89.     filtab                ; init table to idenity
  90. namein    db    20 dup (0)        ; name of the character set
  91. userout    equ    this byte
  92.     filtab                ; init table to idenity
  93. nameout db    20 dup (0)        ; name of the character set
  94. tblptr    dw    0            ; LOAD command
  95. xlines    dw    0            ; LOAD command
  96. linecnt    dw    0            ; LOAD command
  97. badvalue db    cr,lf,'?Bad value on line $'
  98.  
  99. ; Translation tables for byte codes 0a0h..0ffh to map ISO 8859-1 to Code Pages
  100. ; Codes 00h-1fh are 7-bit controls (C0), codes 20h..7eh are ASCII, 7fh DEL is
  101. ; considered to be a control code, 80h..9fh are 8-bit controls (C1).
  102. ; Each table is 96 translatable bytes followed by the table size (96), the
  103. ; ISO announcer ident ('A' and a null here); LATIN5/Cyrillic uses 'L'.
  104.                     ; from ISO 8859-1 Latin-1 to Code Page
  105.                             ; to CP437
  106. L1cp437    db    80h,81h,82h,83h,   84h,85h,86h,87h    ; column 8
  107.     db    88h,89h,8ah,8bh,   8ch,8dh,8eh,8fh
  108.     db    90h,91h,92h,93h,   94h,95h,96h,97h    ; column 9
  109.     db    98h,99h,9ah,9bh,   9ch,9dh,9eh,9fh
  110.     db    20h,0adh,9bh,9ch,  0fh,9dh,7ch,15h    ; column 10
  111.     db    22h,40h,0a6h,0aeh, 0aah,0c4h,3fh,2dh
  112.     db    0f8h,0f1h,0fdh,33h, 27h,0e6h,14h,0fah    ; column 11
  113.     db    2ch,31h,0a7h,0afh, 0ach,0abh,3fh,0a8h
  114.     db    41h,41h,41h,41h,   8eh,8fh,92h,80h    ; column 12
  115.     db    45h,90h,45h,45h,   49h,49h,49h,49h
  116.     db    44h,0a5h,4fh,4fh,  4fh,4fh,99h,58h    ; column 13
  117.     db    4fh,55h,55h,55h,  9ah,59h,3fh,0e1h
  118.     db    85h,0a0h,83h,61h,  84h,86h,91h,87h    ; column 14
  119.     db    8ah,82h,88h,89h,   8dh,0a1h,8ch,8bh
  120.     db    3fh,0a4h,95h,0a2h, 93h,6fh,94h,0f6h    ; column 15
  121.     db    6fh,97h,0a3h,96h,  81h,79h,3fh,98h
  122.     db    96,'A',0            ; 96 byte set, letter ident
  123.  
  124.                             ; to CP850
  125. L1cp850    db    80h,81h,82h,83h,   84h,85h,86h,87h    ; column 8
  126.     db    88h,89h,8ah,8bh,   8ch,8dh,8eh,8fh
  127.     db    90h,91h,92h,93h,   94h,95h,96h,97h    ; column 9
  128.     db    98h,99h,9ah,9bh,   9ch,9dh,9eh,9fh
  129.     db    20h,0adh,0bdh,9ch,  0cfh,0beh,0ddh,0f5h    ; column 10
  130.     db    0f9h,0b8h,0a6h,0aeh, 0aah,0f0h,0a9h,0eeh
  131.     db    0f8h,0f1h,0fdh,0fch, 0efh,0e6h,0f4h,0fah ; column 11
  132.     db    0f7h,0fbh,0a7h,0afh, 0ach,0abh,0f3h,0a8h
  133.     db    0b7h,0b5h,0b6h,0c7h, 8eh,8fh,92h,80h    ; column 12
  134.     db    0d4h,90h,0d2h,0d3h, 0deh,0d6h,0d7h,0d8h
  135.     db    0d1h,0a5h,0e3h,0e0h, 0e2h,0e5h,99h,9eh    ; column 13
  136.     db    9dh,0ebh,0e9h,0eah, 9ah,0edh,0e8h,0e1h
  137.     db    85h,0a0h,83h,0c6h,  84h,86h,91h,87h    ; column 14
  138.     db    8ah,82h,88h,89h,    8dh,0a1h,8ch,8bh
  139.     db    0d0h,0a4h,95h,0a2h, 93h,0e4h,94h,0f6h    ; column 15
  140.     db    9bh,97h,0a3h,96h,   81h,0ech,0e7h,98h
  141.     db    96,'A',0            ; 96 byte set, letter ident
  142.                             ; to CP860
  143. L1cp860    db    80h,81h,82h,83h,   84h,85h,86h,87h    ; column 8
  144.     db    88h,89h,8ah,8bh,   8ch,8dh,8eh,8fh
  145.     db    90h,91h,92h,93h,   94h,95h,96h,97h    ; column 9
  146.     db    98h,99h,9ah,9bh,   9ch,9dh,9eh,9fh
  147.     db    20h,0adh,9bh,9ch,  0fh,59h,7ch,15h    ; column 10
  148.     db    22h,40h,0a6h,0aeh, 0aah,0c4h,3fh,2dh
  149.     db    0f8h,0f1h,0fdh,33h, 27h,0e6h,14h,0fah    ; column 11
  150.     db    2ch,31h,0a7h,0afh, 0ach,0abh,3fh,0a8h
  151.     db    91h,86h,8fh,8eh,   41h,41h,41h,80h    ; column 12
  152.     db    92h,90h,89h,45h,   8bh,98h,49h,49h
  153.     db    44h,0a5h,0a9h,9fh, 8ch,99h,4fh,58h    ; column 13
  154.     db    4fh,9dh,96h,55h,   9ah,59h,3fh,0e1h
  155.     db    85h,0a0h,83h,84h,  61h,61h,61h,87h    ; column 14
  156.     db    8ah,82h,88h,65h,   8dh,0a1h,69h,69h
  157.     db    3fh,0a4h,95h,0a2h, 93h,94h,6fh,0f6h    ; column 15
  158.     db    6fh,97h,0a3h,75h,  81h,79h,3fh,79h
  159.     db    96,'A',0            ; 96 byte set, letter ident
  160.                             ; to CP863
  161. L1cp863    db    80h,81h,82h,83h,   84h,85h,86h,87h    ; column 8
  162.     db    88h,89h,8ah,8bh,   8ch,8dh,8eh,8fh
  163.     db    90h,91h,92h,93h,   94h,95h,96h,97h    ; column 9
  164.     db    98h,99h,9ah,9bh,   9ch,9dh,9eh,9fh
  165.     db    20h,3fh,9bh,9ch,   98h,59h,0a0h,8fh    ; column 10
  166.     db    0a4h,40h,61h,0aeh, 0aah,0c4h,3fh,0a7h
  167.     db    0f8h,0f1h,0fdh,0a6h, 0a1h,0e6h,86h,0fah    ; column 11
  168.     db    0a5h,31h,6fh,0afh, 0ach,0abh,0adh,3fh
  169.     db    8eh,41h,84h,41h,   41h,41h,41h,80h    ; column 12
  170.     db    91h,90h,92h,94h,   49h,49h,0a8h,95h
  171.     db    44h,4eh,4fh,4fh,   99h,4fh,4fh,58h    ; column 13
  172.     db    4fh,9dh,55h,9eh,   9ah,59h,3fh,0e1h
  173.     db    85h,61h,83h,61h,   61h,61h,61h,87h    ; column 14
  174.     db    8ah,82h,88h,89h,   69h,69h,8ch,8bh
  175.     db    3fh,6eh,6fh,0a2h,  93h,6fh,6fh,0f6h    ; column 15
  176.     db    6fh,97h,0a3h,96h,  81h,79h,3fh,79h
  177.     db    96,'A',0            ; 96 byte set, letter ident
  178.                             ; to CP865
  179. L1cp865    db    80h,81h,82h,83h,   84h,85h,86h,87h    ; column 8
  180.     db    88h,89h,8ah,8bh,   8ch,8dh,8eh,8fh
  181.     db    90h,91h,92h,93h,   94h,95h,96h,97h    ; column 9
  182.     db    98h,99h,9ah,9bh,   9ch,9dh,9eh,9fh
  183.     db    20h,0adh,3fh,9ch,  0afh,59h,7ch,15h    ; column 10
  184.     db    22h,40h,0a6h,0aeh, 0aah,0c4h,3fh,0c4h
  185.     db    0f8h,0f1h,0fdh,33h, 27h,0e6h,14h,0fah    ; column 11
  186.     db    2ch,31h,0a7h,03fh, 0ach,0abh,3fh,0a8h
  187.     db    41h,41h,41h,41h,   8eh,8fh,92h,80h    ; column 12
  188.     db    45h,90h,45h,45h,   49h,49h,49h,49h
  189.     db    44h,0a5h,4fh,4fh,  4fh,4fh,99h,58h    ; column 13
  190.     db    9dh,55h,55h,55h,  9ah,59h,3fh,0e1h
  191.     db    85h,0a0h,83h,61h,  84h,86h,91h,87h    ; column 14
  192.     db    8ah,82h,88h,89h,   8dh,0a1h,8ch,8bh
  193.     db    3fh,0a4h,95h,0a2h, 93h,6fh,94h,0f6h    ; column 15
  194.     db    9bh,97h,0a3h,96h,  81h,79h,3fh,98h
  195.     db    96,'A',0            ; 96 byte set, letter ident
  196.                             ; Latin5 to CP866
  197. L5cp866    db    80h,81h,82h,83h,   84h,85h,86h,87h    ; column 8
  198.     db    88h,89h,8ah,8bh,   8ch,8dh,8eh,8fh
  199.     db    90h,91h,92h,93h,   94h,95h,96h,97h    ; column 9
  200.     db    98h,99h,9ah,9bh,   9ch,9dh,9eh,9fh
  201.     db    0ffh,0f0h,3fh,3fh,  0f2h,53h,49h,4fh    ; column 10
  202.     db    4ah,3fh,3fh,48h,   4bh,2dh,0f6h,3fh
  203.     db    80h,81h,82h,83h,   84h,85h,86h,87h    ; column 11
  204.     db    88h,89h,8ah,8bh,   8ch,8dh,8eh,8fh
  205.     db    90h,91h,92h,93h,   94h,95h,96h,97h    ; column 12
  206.     db    98h,99h,9ah,9bh,   9ch,9dh,9eh,9fh
  207.     db    0a0h,0a1h,0a2h,0a3h,0a4h,0a5h,0a6h,0a7h ; column 13
  208.     db    0a8h,0a9h,0aah,0abh,0ach,0adh,0aeh,0afh
  209.     db    0e0h,0e1h,0e2h,0e3h,0e4h,0e5h,0e6h,0e7h ; column 14
  210.     db    0e8h,0e9h,0eah,0ebh,0ech,0edh,0eeh,0efh
  211.     db    0fch,0f1h,3fh,3fh, 0f3h,73h,69h,0f5h    ; column 15
  212.     db    6ah,3fh,3fh,68h,   6bh,15h,0f7h,3fh
  213.     db    96,'L',0            ; 96 byte set, Latin5/Cyrillic
  214.  
  215. ; 128 byte translation tables from Code Pages to ISO 8859-1 Latin1 or Latin5
  216. ; For GRight only (high bit set).
  217.                             ; from Code Page 437
  218. cp437L1    db    0c7h,0fch,0e9h,0e2h, 0e4h,0e0h,0e5h,0e7h ; column 8
  219.     db    0eah,0ebh,0e8h,0efh, 0eeh,0ech,0c4h,0c5h
  220.     db    0c9h,0e6h,0c6h,0f4h, 0f6h,0f2h,0fbh,0f9h ; column 9
  221.     db    0ffh,0d6h,0dch,0a2h, 0a3h,0a5h,3fh,3fh
  222.     db    0e1h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
  223.     db    0bfh,3fh,0ach,0bdh,  0bch,0a1h,0abh,0bbh
  224.     db    16 dup (3fh)                 ; column 11
  225.     db    16 dup (3fh)                 ; column 12
  226.     db    16 dup (3fh)                 ; column 13
  227.     db    3fh,0dfh, 4 dup (3fh),        0b5h,3fh ; column 14
  228.     db    5 dup(3fh),            0f8h,3fh,3fh
  229.     db    3fh,0b1h, 4 dup (3fh),        0f7h,3fh ; column 15
  230.     db    0b0h,0b7h,0b7h,3fh,3fh,        0b2h,3fh,3fh
  231.                              ; from Code Page 850
  232. cp850L1    db    0c7h,0fch,0e9h,0e2h, 0e4h,0e0h,0e5h,0e7h ; column 8
  233.     db    0eah,0ebh,0e8h,0efh, 0eeh,0ech,0c4h,0c5h
  234.     db    0c9h,0e6h,0c6h,0f4h, 0f6h,0f2h,0fbh,0f9h ; column 9
  235.     db    0ffh,0d6h,0dch,0f8h, 0a3h,0d8h,0d7h,3fh
  236.     db    0e1h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
  237.     db    0bfh,0aeh,0ach,0bdh, 0bch,0a1h,0abh,0bbh
  238.     db    5 dup (3fh),              0c1h,0c2h,0c0h ; column 11
  239.     db    0a9h, 4 dup (3fh),      0a2h,0a5h,3fh
  240.     db    6 dup (3fh),0e3h,0c3h, 7 dup (3fh),0a4h     ; column 12
  241.     db    0f0h,0d0h,0cah,0cbh, 0c8h,0b9h,0cdh,0ceh ; column 13
  242.     db    0cfh, 4 dup (3fh),       0a6h,0cch,3fh
  243.     db    0d3h,0dfh,0d4h,0d2h, 0f5h,0d5h,0b5h,0feh ; column 14
  244.     db    0deh,0dah,0dbh,0d9h, 0fdh,0ddh,0afh,0b4h
  245.     db    0adh,0b1h,3dh,0beh,  0b6h,0a7h,0f7h,0b8h ; column 15
  246.     db    0b0h,0a8h,0b7h,0b9h, 0b3h,0b2h,3fh,20h
  247.                              ; from Code Page 860
  248. cp860L1    db    0c7h,0fch,0e9h,0e2h, 0e3h,0e0h,0c1h,0e7h ; column 8
  249.     db    0eah,0cah,0e8h,0cch, 0d4h,0ech,0c3h,0c2h
  250.     db    0c9h,0c0h,0c8h,0f4h, 0f5h,0f2h,0dah,0f9h ; column 9
  251.     db    0cdh,0d5h,0dch,0a2h, 0a3h,0d9h,3fh,0d3h
  252.     db    0e1h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
  253.     db    0bfh,0d2h,0ach,0bdh, 0bch,0a1h,0abh,0bbh
  254.     db    16 dup (3fh)                 ; column 11
  255.     db    16 dup (3fh)                 ; column 12
  256.     db    16 dup (3fh)                 ; column 13
  257.     db    3fh,0dfh, 4 dup (3fh),        0b5h,3fh ; column 14
  258.     db    5 dup(3fh),            0f8h,3fh,3fh
  259.     db    3fh,0b1h, 4 dup (3fh),        0f7h,3fh ; column 15
  260.     db    0b0h,0b7h,0b7h,3fh,  3fh,0b2h,3fh,3fh
  261.                              ; from Code Page 863
  262. cp863L1    db    0c7h,0fch,0e9h,0e2h, 0c2h,0e0h,0b6h,0e7h ; column 8
  263.     db    0eah,0ebh,0e8h,0efh, 0eeh,3dh,0c0h,0a7h
  264.     db    0c9h,0c8h,0cah,0f4h, 0cbh,0cfh,0fbh,0f9h ; column 9
  265.     db    0a4h,0d4h,0dch,0a2h, 0a3h,0d9h,0dbh,3fh
  266.     db    0a6h,0b4h,0f3h,0fah, 0a8h,0b8h,0b3h,0afh ; column 10
  267.     db    0ceh,3fh,0ach,0bdh,  0bch,0beh,0abh,0bbh
  268.     db    16 dup (3fh)                 ; column 11
  269.     db    16 dup (3fh)                 ; column 12
  270.     db    16 dup (3fh)                 ; column 13
  271.     db    3fh,0dfh, 4 dup (3fh),        0b5h,3fh ; column 14
  272.     db    5 dup(3fh),            0f8h,3fh,3fh
  273.     db    3fh,0b1h, 4 dup (3fh),        0f7h,3fh ; column 15
  274.     db    0b0h,0b7h,0b7h,3fh,  3fh,0b2h,3fh,3fh
  275.                                   ; from Code Page 865
  276. cp865L1    db    0c7h,0fch,0e9h,0e2h, 0e4h,0e0h,0e5h,0e7h ; column 8
  277.     db    0eah,0ebh,0e8h,0efh, 0eeh,0ech,0c4h,0c5h
  278.     db    0c9h,0e6h,0c6h,0f4h, 0f6h,0f2h,0fbh,0f9h ; column 9
  279.     db    0ffh,0d6h,0dch,0f8h, 0a3h,0d8h,3fh,3fh
  280.     db    0e2h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
  281.     db    0bfh,3fh,0ach,0bdh,  0bch,0a1h,0abh,0a4h
  282.     db    16 dup (3fh)                 ; column 11
  283.     db    16 dup (3fh)                 ; column 12
  284.     db    16 dup (3fh)                 ; column 13
  285.     db    3fh,0dfh, 4 dup (3fh),        0b5h,3fh ; column 14
  286.     db    5 dup(3fh),            0f8h,3fh,3fh
  287.     db    3fh,0b1h, 4 dup (3fh),        0f7h,3fh ; column 15
  288.     db    0b0h,0b7h,0b7h,3fh,  3fh,0b2h,3fh,3fh
  289.                      ; from Code Page 866 to LATIN5
  290. cp866L5    db    0b0h,0b1h,0b2h,0b3h, 0b4h,0b5h,0b6h,0b7h ; column 8
  291.     db    0b8h,0b9h,0bah,0bbh, 0bch,0bdh,0beh,0bfh
  292.     db    0c0h,0c1h,0c2h,0c3h, 0c4h,0c5h,0c6h,0c7h ; column 9
  293.     db    0c8h,0c9h,0cah,0cbh, 0cch,0cdh,0ceh,0cfh
  294.     db    0d0h,0d1h,0d2h,0d3h, 0d4h,0d5h,0d6h,0d7h ; column 10
  295.     db    0d8h,0d9h,0dah,0dbh, 0dch,0ddh,0deh,0dfh
  296.     db    16 dup (3fh)                 ; column 11
  297.     db    16 dup (3fh)                 ; column 12
  298.     db    16 dup (3fh)                 ; column 13
  299.     db    0e0h,0e1h,0e2h,0e3h, 0e4h,0e5h,0e6h,0e7h ; column 14
  300.     db    0e8h,0e9h,0eah,0ebh, 0ech,0edh,0eeh,0efh
  301.     db    0a1h,0f1h,0a4h,0f4h, 0a7h,0f7h,0aeh,0feh ; column 15
  302.     db    4 dup (3fh),         0f0h,3fh,3fh,0a0h
  303. data    ends
  304.  
  305. code    segment
  306.     extrn    decout:near, isfile:near, newfn:near, comnd:near, atoi:near
  307.     extrn    ermsg:near, clrfln:near, frpos:near, kbpr:near, perpr:near
  308.  
  309.     assume  cs:code, ds:data, es:nothing
  310.  
  311. ; Set register SI to the offset of the ISO Latin-1 table appropriate to the
  312. ; currently active Code Page. Defaults to CP437 if no CP found.
  313. LATIN1    proc    near
  314.     push    ax
  315.     mov    ax,flags.chrset
  316.     mov    si,offset L1cp437    ; assume CP437
  317.     cmp    ax,437            ; current Code Page is 437?
  318.     je    latin1x            ; e = yes
  319.     mov    si,offset L1cp850    ; assume CP850
  320.     cmp    ax,850            ; current Code Page is 850?
  321.     je    latin1x            ; e = yes
  322.     mov    si,offset L1cp860    ; assume CP860
  323.     cmp    ax,860            ; current Code Page is 860?
  324.     je    latin1x            ; e = yes
  325.     mov    si,offset L1cp863    ; assume CP863
  326.     cmp    ax,863            ; current Code Page is 863?
  327.     je    latin1x            ; e = yes
  328.     mov    si,offset L1cp865    ; assume CP865
  329.     cmp    ax,865            ; current Code Page is 865?
  330.     je    latin1x            ; e = yes
  331.     mov    si,offset L5cp866    ; assume CP866
  332.     cmp    ax,866            ; current Code Page is 866?
  333.     je    latin1x            ; e = yes
  334.     mov    si,offset userin    ; user loadable incoming table
  335.     cmp    ax,1            ; User-defined table?
  336.     je    latin1x            ; e = yes
  337.     mov    si,offset L1cp437    ; default to CP437
  338. latin1x:pop    ax
  339.     ret
  340. LATIN1    endp
  341.  
  342. ; Set reg BX to offset of table for Code Page to ISO 8859-1 Latin1/Latin5
  343. cplatin proc    near
  344.     push    ax
  345.     mov    ax,flags.chrset
  346.     mov    bx,offset cp437L1    ; assume CP437
  347.     cmp    ax,437            ; current Code Page is 437?
  348.     je    cplatx            ; e = yes
  349.     mov    bx,offset cp850L1    ; assume CP850
  350.     cmp    ax,850            ; current Code Page is 850?
  351.     je    cplatx            ; e = yes
  352.     mov    bx,offset cp860L1    ; assume CP860
  353.     cmp    ax,860            ; current Code Page is 860?
  354.     je    cplatx            ; e = yes
  355.     mov    bx,offset cp863L1    ; assume CP863
  356.     cmp    ax,863            ; current Code Page is 863?
  357.     je    cplatx            ; e = yes
  358.     mov    bx,offset cp865L1    ; assume CP865
  359.     cmp    ax,865            ; current Code Page is 865?
  360.     je    cplatx            ; e = yes
  361.     mov    bx,offset cp866L5    ; assume CP866 for LATIN5
  362.     cmp    ax,866            ; corrent Code Page is 866?
  363.     je    cplatx            ; e = yes
  364.     mov    bx,offset userout    ; user loadable outgoing table
  365.     cmp    ax,1            ; User-table?
  366.     je    cplatx            ; e = yes
  367.     mov    bx,offset cp437L1    ; default to CP437
  368. cplatx:    pop    ax
  369.     ret
  370. cplatin endp
  371.  
  372. ; Output the chars in a packet, called only by receiver code.
  373. ; Enter with SI equal to pktinfo structure pointer.
  374. PTCHR:    mov    decoutp,offset outbuf  ; routine to call when buffer gets full
  375.     jmp    short decode
  376.  
  377.  
  378. ; Dodecoding.
  379. ; Decode packet to buffer decbuf. Overflow of decbuf yields error ???
  380. ; Modifies regs BX, CX.
  381. ; Enter with SI equal to pktinfo structure pointer.
  382. dodec    proc    near
  383.     push    ax            ; save reg
  384.     mov    decoutp,offset dnulr    ; routine to dump buffer (null)
  385.     call    decode
  386.     push    bx
  387.     mov    bx,dbufpnt        ; next char position
  388.     mov    byte ptr [bx],0        ; null terminator
  389.     pop    bx
  390.      pop    ax
  391.     ret
  392. dodec    endp
  393.  
  394. dnulr:    ret                ; dummy buffer emptier
  395.  
  396. ; Enter with [si].datlen = length of data, [si].datadr = address of data,
  397. ; DECOUTP = pointer to routine which writes output buffer
  398. ; Returns DBUFPNT = pointer to output buffer address (offset part)
  399. ; All packets are decoded except I, S, and A types.
  400. ; Flushes output buffer before returning.
  401. ; Returns carry clear if success, otherwise carry set
  402. decode    proc    near
  403.     push    si
  404.     push    di
  405.     push    es
  406.     push    dx
  407.     push    ds
  408.     pop    es            ; set es to data segment
  409.     mov    dchrcnt,length decbuf    ; size of output buffer
  410.     mov    dbufpnt,offset decbuf ; decoded data placed here pending output
  411.     mov    cx,[si].datlen        ; length of source buffer data
  412.     mov    si,[si].datadr        ; source buffer address
  413.     mov    di,dbufpnt        ; destination of data
  414.     mov    bl,trans.squote        ; regular quote char
  415.     xor    dh,dh            ; assume no quote char
  416.     cmp    trans.ebquot,'N'    ; any 8-bit quoting?
  417.     je    decod1            ; e = no quoting
  418.     cmp    trans.ebquot,'Y'    ; or not doing it?
  419.     je    decod1            ; e = no need to quote
  420.     mov    dh,trans.ebquot        ; otherwise use 8-bit quote char
  421.  
  422. decod1:    mov    rptct,1            ; reset repeat count
  423.     or    cx,cx            ; any more chars in source?
  424.     jg    decod2            ; g = yes
  425.     jmp    decod6            ; else, we're through
  426. decod2:    cld                ; forward direction
  427.     lodsb                ; pick up a char
  428.     dec    cx            ; count number left
  429.     cmp    al,trans.rptq        ; repeat quote char?
  430.     jne    dcod21            ; ne = no, continue processing it
  431.     or    al,al            ; doing repeat quoting? (0 if no)
  432.     jz    dcod21            ; z = no, skip this part
  433.     lodsb                ; get the size
  434.     dec    cx            ; modify buffer count
  435.     sub    al,20H            ; make printable
  436.     mov    rptct,al        ; remember how many repetitions
  437.     lodsb                ; get the char to repeat
  438.     dec    cx            ; modify buffer count
  439.  
  440. dcod21:    xor    ah,ah            ; assume no 8-bit quote char
  441.     cmp    al,dh            ; is this the 8-bit quot char?
  442.     jne    decod3            ; ne = no
  443.     lodsb                ; yes, get the real character
  444.     dec    cx            ; decrement # chars in packet
  445.     mov    ah,80H            ; turn on 8-bit quot char flag
  446. decod3: cmp    al,bl            ; quote char?
  447.     jne    decod4            ; ne = no, proceed
  448.     lodsb                ; get the quoted character
  449.     dec    cx            ; decrement # of chars in packet
  450.     or    ah,al            ; save parity (combine with prefix)
  451.     and    ax,807fh        ; only parity in ah, remove it in al
  452.     cmp    al,bl            ; quote char?
  453.     je    decod4            ; e = yes, just go write it out
  454.     cmp    al,dh            ; 8-bit quote char?
  455.     je    decod4            ; e = yes, just go write it out
  456.     cmp    al,trans.rptq        ; repeat quote character?
  457.     je    decod4            ; e = yes, just write it out
  458.     cmp    al,3fh            ; char less than '?' ?
  459.     jb    decod4            ; b = yes; leave it intact
  460.     cmp    al,5fh            ; char greater than '_' ?
  461.     ja    decod4            ; a = yes; leave it alone
  462.     add    al,40H            ; make it a control char again
  463.     and    al,7FH            ; modulo 128 (includes DEL)
  464. decod4: or    al,ah            ; or in parity
  465.     push    cx
  466. decod5:    xor    ch,ch
  467.     mov    cl,rptct        ; number of chars to be written
  468.     jcxz    decod5c            ; z = none
  469.     cmp    cx,dchrcnt        ; needed vs space available
  470.     jbe    decod5a            ; be = enough space for rptct chars
  471.     mov    cx,dchrcnt        ; insufficient space, do dchrcnt
  472. decod5a:sub    rptct,cl        ; reduce number left to be written
  473.     sub    dchrcnt,cx        ; reduce output free space
  474.     pushf                ; save sub status flags
  475.     shr    cx,1
  476.     jnc    decod5b            ; nc = an even number
  477.     stosb                ; store the odd byte
  478.     jcxz    decod5d            ; z = nothing else to write
  479. decod5b:mov    ah,al            ; make a copy for word writes
  480.     rep    stosw            ; store cx words
  481. decod5d:popf                ; recover flags from sub dchrcnt,cx
  482.     jg    decod5c            ; g = space remaining in output buffer
  483.     push    dx            ; flush output buffer
  484.     push    bx
  485.     push    ax            ; save the char
  486.     call    decoutp            ; output the buffer
  487.     pop    ax            ; recover repeated char
  488.     pop    bx
  489.     pop    dx
  490.     jc    decod7            ; c = error if disk is full
  491.     mov    di,dbufpnt
  492.     jmp    short decod5        ; see if more chars need be written
  493. decod5c:pop    cx            ; recover main loop counter
  494.     jmp    decod1            ; get next source character
  495.     
  496. decod6:    mov    dbufpnt,di        ; flush buffer before exiting decode
  497.     push    cx
  498.     call    decoutp            ; flush output buffer before final ret
  499. decod7:    pop    cx
  500.  
  501.     pop    dx
  502.     pop    es
  503.     pop    di
  504.     pop    si
  505.     ret                ; return successfully if carry clear
  506. decode    endp
  507.                     ; output decbuf, reset bufpnt & chrcnt
  508. outbuf:    mov    cx,length decbuf    ; get full size of buffer
  509.     sub    cx,dchrcnt        ; minus space remaining = # to write
  510.     jg    outbu2            ; g = something to do
  511.     jmp    outbf1
  512. outbu2:    mov    dx,offset decbuf    ; address of buffer
  513.     cmp    trans.xtype,1        ; File Type Binary?
  514.     je    outbu5            ; e = yes, no translation
  515.     cmp    flags.destflg,1        ; disk destination?
  516.     je    outbu5            ; e = yes, DOS will do it
  517.     cmp    flags.eofcz,0        ; end on Control-Z?
  518.     je    outbu5            ; e = no
  519.     push    cx            ; else map Control-Z to space
  520.     push    di
  521.     push    es
  522.     push    ds
  523.     pop    es            ; data to es
  524.     mov    di,dx            ; scan buffer es:di, cx chars worth
  525.     mov    al,ctlz            ; look for Control-Z
  526.     cld
  527. outbu3:    repne    scasb
  528.     jne    outbu4            ; ne = found no Control-Z's
  529.     mov    byte ptr [di-1],' '    ; replace Control-Z with space
  530.     jcxz    outbu4            ; z = examined all chars
  531.     jmp    short outbu3        ; until examined everything
  532. outbu4:    pop    es
  533.     pop    di
  534.     pop    cx
  535.                     ; Character set translation section
  536. outbu5:    cmp    trans.xtype,1        ; File Type Binary?
  537.     je    outbu7            ; e = yes, no translation
  538.     cmp    trans.xchset,0        ; Transfer Transparent?
  539.     je    outbu7            ; e = yes, no translation
  540.     push    cx
  541.     push    si
  542.     push    di
  543.     call    latin1            ; set si to Xfr char set to CP table
  544.     mov    bx,si            ; set to bx for xlat
  545.     mov    si,offset decbuf    ; scan this buffer
  546.     mov    di,si
  547.     push    es
  548.     push    ds
  549.     pop    es
  550.     cld
  551. outbu6:    lodsb                ; get a char
  552.     test    al,80h            ; high bit set?
  553.     jz    outbu6a            ; z = no, do not translate
  554.     and    al,not 80h        ; clear high bit
  555.     xlatb                ; translate via bx table
  556. outbu6a:stosb                ; store char
  557.     loop    outbu6            ; do all concerned
  558.     pop    es
  559.     pop    di
  560.     pop    si
  561.     pop    cx
  562.  
  563. outbu7:    push    bx
  564.     mov    bx,diskio.handle    ; file handle
  565.     mov    ah,write2        ; write cx bytes
  566.     int    dos
  567.     pop    bx
  568.     jc    outbf0            ; c set means writing error
  569.     cmp    ax,cx            ; did we write all the bytes?
  570.     je    outbf1            ; e = yes
  571.     push    bx
  572.     mov    bx,offset decbuf
  573.     add    bx,ax            ; look at break character
  574.     cmp    byte ptr [bx],ctlz    ; ended on Control-Z?
  575.     pop    bx
  576.     je    outbf1            ; e = yes, say no error
  577. outbf0: mov    dx,offset erms13    ; Error writing device
  578.     cmp    flags.xflg,0        ; writing to screen?
  579.     jne    outbf0a            ; ne = yes
  580.     cmp    flags.destflg,0        ; writing to printer?
  581.     jne    outbf0a            ; ne = no
  582.     mov    dx,offset ermes9    ; Printer not ready message
  583. outbf0a:call    ermsg
  584.     stc                ; return failure
  585.     ret
  586.  
  587. outbf1:    add    tfilsz,cx        ; count received chars
  588.     adc    tfilsz+2,0
  589.     test    flags.remflg,dserial    ; serial mode display?
  590.     jnz    outb11            ; nz = yes, skip kbyte and % displays
  591.     cmp    flags.xflg,0        ; receiving to screen?
  592.     jne    outb11            ; ne = yes
  593.     call    kbpr            ; display kilobytes done
  594.     call    perpr            ; display percentage done
  595. outb11:    mov    dbufpnt,offset decbuf    ; address for beginning
  596.     mov    dchrcnt,length decbuf    ; size of empty buffer
  597.     clc                ; return success
  598.     ret
  599.  
  600. ; Get chars from file, encode them to pktinfo structure pointed to by si
  601.  
  602. gtchr:    mov    [si].datlen,0        ; say no output data yet
  603.     cmp    filflg,0        ; is there anything in the buffer?
  604.     jne    gtchr0            ; ne = yes, use that material first
  605.     call    inbuf            ; do initial read from source
  606.     jc    gtchr1            ; c = no more chars, go return EOF
  607. gtchr0:    mov    encinp,offset inbuf    ; buffer refiller routine
  608.     jmp    short encode
  609.  
  610. gtchr1:    mov    [si].datlen,0        ; report EOF
  611.     mov    flags.eoflag,1        ; say eof
  612.     stc                ; return failure
  613.     ret
  614.  
  615. ; Do encoding.
  616. ; Enter with CX = data size, source of data is encbuf, si is pktinfo ptr.
  617. ; Writes output to area pointed to by [si].datadr.
  618. ; Returns char count in cx and [si].datlen with carry clear if success,
  619. ; else carry set if overflow.
  620. ; SI is preserved
  621. doenc:    clc
  622.     jcxz    doen0            ; cx = 0 means nothing to encode
  623.     mov    echrcnt,cx        ; number of bytes of source data
  624.     mov    ebufpnt,offset encbuf    ; source of data
  625.     mov    encinp,offset nulref    ; null routine for refilling buffer
  626.     call    encode            ; make a packet with size in AX
  627.     mov    cx,ax
  628. doen0:    ret
  629.  
  630. nulref:    mov    echrcnt,0        ; no data to return
  631.     stc
  632.     ret
  633.  
  634. ; encode - writes data portion of kermit packet into [[si].datadr].
  635. ; expects encinp to contain the address of a routine to refill the buffer,
  636. ; chrcnt to be the # of chars in the buffer, trans.maxdat to contain
  637. ; the maximum size of the data packet, ebufpnt to contain a pointer to
  638. ; the source of the characters, and [si].datadr to be output address.
  639. ; Returns: AX = the number of characters actually written to the buffer
  640. ; All packets except I, S, and A types are encoded.
  641. ; Returns carry clear for success, carry set otherwise.
  642.  
  643. encode    proc    near
  644.     push    si            ; save caller's si
  645.     mov    al,trans.rptq        ; repeat quote character
  646.     mov    tmprptq,al        ; working copy
  647.     mov    rptct,1            ; number of times char is repeated
  648.     mov    rptval,0        ; value of repeated char
  649.     mov    cx,trans.maxdat        ; maximum packet size
  650.     push    ds
  651.     pop    es            ; make es:di point to data segment
  652.     mov    di,[si].datadr        ; address of output buffer
  653.     mov    temp,di            ; remember output buffer start address
  654.     mov    si,ebufpnt        ; pointer into source buffer
  655.     mov    dl,trans.rquote        ; send quote char
  656.     xor    dh,dh            ; assume no 8-bit quoting
  657.     cmp    trans.ebquot,'N'    ; refusing 8-bit quoting?
  658.     je    encod1            ; e = yes
  659.     cmp    trans.ebquot,'Y'    ; or can but won't?
  660.     je    encod1            ; e = yes
  661.     mov    dh,0ffh            ; remember we have to do it
  662. encod1: or    cx,cx            ; any space left in output buffer?
  663.     jg    encod2            ; g = yes
  664.     mov    ax,di            ; current output location
  665.     sub    ax,temp            ; minus start of buffer, ret cnt in AX
  666.     mov    ebufpnt,si        ; update pointer into source buffer
  667.     pop    si            ; restore caller's si
  668.     mov    [si].datlen,ax
  669.     clc                ; success
  670.     ret
  671.  
  672. encod2: cmp    echrcnt,0        ; any data in buffer?
  673.     jg    encod3            ; g = yes, skip over buffer refill
  674.     call    encinp            ; get another buffer full
  675.     jnc    encod2a            ; nc = success
  676.  
  677. encod8:    pop    si            ; restore user's si
  678.     sub    di,temp            ; minus start of buffer
  679.     or    di,di            ; buffer empty?
  680.     jz    encod9            ; z = yes
  681.     mov    ax,di            ; report size encoded
  682.     mov    [si].datlen,ax
  683.     clc                ; success
  684.     ret                ; return success
  685. encod9: xor    ax,ax            ; empty buffer
  686.         mov    flags.eoflag,1        ; set eof flag
  687.     mov    filflg,al        ; nothing in input buffer
  688.     mov    [si].datlen,ax
  689.     stc                ; failure
  690.     ret                ; return failure
  691.  
  692. encod2a:mov    si,ebufpnt        ; update position in source buffer
  693.     cmp    echrcnt,0         ; any characters returned?
  694.     je    encod8            ; e = none, assume eof
  695.  
  696. encod3: dec    echrcnt            ; decrement input count
  697.     cld                ; forward direction
  698.     lodsb
  699.     cmp    al,'Z'-40H        ; is this a control-Z?
  700.     jne    encd30            ; ne = no, skip eof-processing
  701.     cmp    flags.eofcz,0           ; is a Control-Z an end of file?
  702.     je    encd30            ; e = no
  703.     cmp    trans.xtype,1        ; file type binary?
  704.     je    encd30            ; e = yes, send as is
  705.     mov    flags.eoflag,1        ; yes, set eof flag
  706.     mov    filflg,0        ; say no more source data in buffer
  707.     mov    echrcnt,0        ; ditto
  708.     jmp    short encod8        ; set character count and return
  709.  
  710. encd30: cmp    tmprptq,0        ; doing repeat prefixing? 
  711.     je    encd3x            ; e = no
  712.     cmp    echrcnt,0        ; doing the last character?
  713.     jle    encd31            ; le = yes, there is no next character
  714.     cmp    rptct,94        ; max number that we can put in a byte
  715.     je    encd31            ; e = at that limit
  716.     cmp    al,[si]            ; is current char == next char?
  717.     jne    encd31            ; ne = no, break repeating
  718.     inc    rptct            ; number of times char appears
  719.     mov    rptval,al        ; remember the character
  720.     jmp    encod1            ; keep checking for more
  721.  
  722. encd31:    cmp    rptct,1            ; were previous characters repeats?
  723.     je    encd3x            ; e = no, so just add this char
  724.     cmp    rptct,3            ; within bounds for repeat prefixing?
  725.     jge    encd32            ; ge = yes, use repeat prefixing
  726.     mov    al,rptct        ; number of copies
  727.     xor    ah,ah            ; push back
  728.     sub    si,ax            ; not enough characters to warrant it
  729.     mov    rptval,0        ; clear out this value
  730.     mov    tmprptq,0        ; pretend we're not doing prefixing
  731.     add    echrcnt,ax        ; adjust input buffer pointer
  732.     jmp    encod1            ; reprocess those characters
  733.  
  734. encd32:    push    ax            ; do repeat prefixing - save data
  735.     mov    al,trans.rptq        ; insert repeat prefix char
  736.     stosb
  737.     dec    cx            ; account for it in buffer size
  738.     mov    al,rptct        ; get the repeat count
  739.     add    al,20H            ; make it printable
  740.     stosb                ; insert into buffer
  741.     dec    cx
  742.     pop    ax            ; get back the actual character
  743.     mov    rptct,1            ; reset repeat count
  744.     mov    rptval,0        ; and this
  745. encd3x:    or    dh,dh            ; doing 8-bit quoting?
  746.     jz    encod4            ; z = no, forget this
  747.     test    al,80h            ; parity on?
  748.     jz    encod4            ; z = no, don't bother with this
  749.     and    al,7fh            ; turn off parity
  750.     mov    ah,trans.ebquot        ; get quote char
  751.     mov    [di],ah            ; put in packet
  752.     inc    di
  753.     dec    cx            ; decrement # of chars left
  754. encod4:    mov    ah,al            ; save character
  755.     and    ah,80h            ; only parity
  756.     and    al,7fh            ; turn off parity in character
  757.     cmp    al,' '            ; compare to a space
  758.     jb    encod5            ; b = control char
  759.     cmp    al,del            ; delete?
  760.     je    encod5            ; e = yes, go quote it
  761.     cmp    al,dl            ; quote char?
  762.     je    encod6            ; e = yes, go add it
  763.     or    dh,dh            ; doing 8-bit quoting?
  764.     jz    encd41            ; z = no, don't translate it
  765.     cmp    al,trans.ebquot        ; 8-bit quote char?
  766.     je    encod6            ; e = yes, just output with quote
  767. encd41:    cmp    trans.rptq,0        ; doing repeat prefixing?
  768.     je    encod7            ; e = no, don't check for quote char
  769.     cmp    al,trans.rptq        ; repeat quote character?
  770.     je    encod6            ; e = yes, then quote it
  771.     jmp    short encod7        ; else don't quote it
  772.  
  773. encod5:    xor    al,40h            ; control char, uncontrollify
  774. encod6:    mov    [di],dl            ; insert control quote char
  775.     inc    di
  776.     dec    cx
  777. encod7:    or    al,ah            ; put parity back
  778.     stosb
  779.     dec    cx            ; decrement output buffer counter
  780.     cmp    rptct,1            ; one occurence of this char?
  781.     jne    encd7x            ; ne = no
  782.     mov    al,trans.rptq        ; real repeat quote char
  783.     mov    tmprptq,al        ; restore repeat quote char
  784.     jmp    encod1            ; loop around for some more
  785. encd7x:    dec    rptct            ; count another entry of this char
  786.     jmp    encod1            ; with quoting and all
  787. encode    endp 
  788.  
  789. ; Fill encode source buffer, report KB and percentage done.
  790. ; Return carry clear for success
  791. ; modifies ax
  792. inbuf    proc    near
  793.     cmp    flags.eoflag,0        ; reached the end?
  794.     je    inbuf0            ; e = no
  795.     stc                ; return failure
  796.     ret
  797. inbuf0:    push    dx
  798.     push    bx
  799.     push    cx
  800.     mov    bx,diskio.handle    ; get file handle
  801.     mov    cx,buffsz        ; record size
  802.     mov    dx,offset buff        ; buffer
  803.     mov    ebufpnt,dx        ; buffer pointer
  804.     mov    ah,readf2        ; read a record
  805.     int    dos
  806.     jnc    inbuf7            ; nc = no error
  807.     mov    flags.cxzflg,'X'    ; error, set ^X flag
  808.      jmp    short inbuf1        ; and truncate the file here
  809. inbuf7:    or    ax,ax            ; any bytes read?
  810.     jnz    inbuf2            ; nz = yes (the number read)
  811. inbuf1:    mov    flags.eoflag,1        ; set End-of-File
  812.     mov    filflg,0        ; buffer empty
  813.     mov    echrcnt,0        ; zero bytes left in buffer
  814.     pop    cx
  815.     pop    bx
  816.     pop    dx
  817.     stc                ; failure
  818.     ret
  819. inbuf2:    add    tfilsz,ax        ; total the # bytes transferred so far
  820.     adc    tfilsz+2,0        ; it's a double word
  821.     mov    echrcnt,ax        ; number of chars read from file
  822.     mov    filflg,1        ; buffer not empty
  823.     test    flags.remflg,dserial    ; serial display mode?
  824.     jnz    inbuf3            ; nz = yes, skip kbyte and % display
  825.     push    si
  826.     push     ax
  827.     call    kbpr            ; show kilobytes sent
  828.     call    perpr            ; show percent sent
  829.     pop    ax
  830.     pop    si
  831.                     ; Character set translation section
  832. inbuf3:    cmp    trans.xchset,0        ; Transparent transfer char set?
  833.     je    inbuf6            ; e = yes, no translation
  834.     cmp    trans.xtype,1        ; File Type Binary?
  835.     je    inbuf6            ; e = yes, no translation
  836.     push    ax            ; save buffer count
  837.     mov    cx,ax            ; loop counter
  838.     push    si
  839.     push    di
  840.     call    cplatin            ; set bx to offset CP to Xfr chr table
  841.     mov    si,offset buff        ; scan this buffer
  842.     mov    di,si
  843.     push    es
  844.     push    ds
  845.     pop    es
  846.     cld
  847. inbuf4:    lodsb                ; get a char
  848.     test    al,80h            ; high bit set?
  849.     jz    inbuf5            ; z = no, no translation
  850.     and    al,not 80h        ; remove high bit
  851.     xlatb                ; translate via bx table
  852. inbuf5:    stosb                ; store char
  853.     loop    inbuf4            ; do all concerned
  854.     pop    es
  855.     pop    di
  856.     pop    si
  857.     pop    ax
  858. inbuf6:    pop    cx
  859.     pop    bx
  860.     pop    dx
  861.     clc                ; success
  862.     ret
  863. inbuf    endp
  864.  
  865.  
  866. ; GETFIL, called only by send code
  867. ; Enter with raw filename pattern in diskio.string
  868. ; Returns carry clear if success, else carry set
  869. getfil    proc    near
  870.     mov    filflg,0        ; say nothing is in the buffer
  871.     mov    flags.eoflag,0        ; not the end of file
  872.     mov    dx,offset diskio.dta    ; data transfer address
  873.     mov    ah,setdma        ; set disk transfer address
  874.     int    dos
  875.     xor    cx,cx            ; attributes: find only normal files
  876.     mov    dx,offset diskio.string ; filename string (may have wild cards)
  877.     mov    ah,first2        ; DOS 2.0 search for first
  878.     int    dos            ; get file's characteristics
  879.     pushf                ; save c flag
  880.     mov    ah,setdma        ; reset dta address
  881.     mov    dx,offset buff        ; restore dta
  882.     int    dos
  883.     popf                ; restore status of search for first
  884.     jnc    getfi1            ; nc = ok so far
  885.     ret                ; else take error exit
  886. getfi1:    jmp    getfcom            ; do common code
  887. getfil    endp
  888.  
  889.  
  890. ; GTNFIL called by send code to get next file.
  891. ; Returns carry clear for success, carry set for failure.
  892. gtnfil    proc    near
  893.     cmp    flags.cxzflg,'Z'    ; Did we have a ^Z?
  894.     jne    gtnfi1            ; ne = no, else done sending files
  895.     stc                ; carry set for failure
  896.     ret                ; take failure exit
  897.  
  898. gtnfi1:    xor    al,al
  899.     mov    filflg,al        ; Nothing in the DMA
  900.     mov    flags.eoflag,al        ; Not the end of file
  901.     mov    dx,offset diskio.dta    ; point at dta
  902.     mov    ah,setdma        ; set the dta address
  903.     int    dos
  904.     mov    ah,next2        ; DOS 2.0 search for next
  905.     int    dos
  906.     pushf                ; save carry flag
  907.     mov    ah,setdma        ; restore dta
  908.     mov    dx,offset buff
  909.     int    dos
  910.     popf                ; recover carry flag
  911.     jnc    getfcom            ; nc = success, do common code
  912.     ret                ; carry    set means no more files found
  913. gtnfil    endp
  914.                     ; worker for getfil, gtnfil
  915. getfcom    proc    near
  916.     push    si
  917.     push    di
  918.     mov    dx,offset diskio.string    ; original file spec (may be wild)
  919.     mov    di,offset templp    ; place for path part
  920.     mov    si,offset templf    ; place for filename part
  921.     call    fparse            ; split them
  922.     mov    si,offset diskio.fname    ; current filename from DOS
  923.     call    strcat            ; (di)= local path + diskio.fname
  924.     mov    di,offset encbuf    ; name to send to host (no path)
  925.     call    strcpy              ; new string = old path + DOS's filename
  926.     push    bx
  927.     push    cx
  928.     test    flags.remflg,dquiet    ; quiet display?
  929.     jnz    getfco1            ; e = yes, do not display filename
  930.     call    clrfln            ; position cursor & blank out the line
  931.     mov    dx,offset templp
  932.     call    prtasz
  933. getfco1:call    newfn            ; update encbuf with "send as" name
  934.     pop    cx
  935.     pop    bx
  936.     mov    ah,open2        ; file open
  937.     xor    al,al            ; 0 = open readonly
  938.     cmp    dosnum,300h        ; at or above DOS 3?
  939.     jb    getfco2            ; b = no, so no shared access
  940.     or    al,40h            ; open readonly, deny none
  941. getfco2:mov    dx,offset templp    ; filename string with path
  942.     int    dos
  943.     jc    getfco3            ; c = failed to open the file
  944.     mov    diskio.handle,ax    ; save file handle
  945.     xor    ax,ax
  946.     mov    tfilsz,ax        ; set bytes sent to zero
  947.     mov    tfilsz+2,ax
  948.     mov    ax,-1            ; get a minus one
  949.     mov    oldkbt,ax
  950.     mov    oldper,ax
  951.     clc                ; carry clear for success
  952. getfco3:pop    si
  953.     pop    di
  954.     ret
  955. getfcom    endp
  956.  
  957. ; Get the file name from the data portion of the F packet or from locally
  958. ; specified override filename (in auxfile), displays the filename, does any
  959. ; manipulation of the filename necessary, including changing the name to
  960. ; prevent collisions. Returns carry clear for success. Failures return
  961. ; carry set with dx pointing at error message text.
  962. ; Called by file receive module in mssrcv.asm.
  963.  
  964. gofil    proc    near
  965.     mov    si,offset decbuf    ; filename in packet
  966.     mov    di,offset diskio.string    ; place where prtfn finds name
  967.     call    strcpy            ; copy pkt filename to diskio.string
  968.     mov    di,offset fsta.xname    ; statistics external filespec area
  969.     call    strcpy            ; record external name
  970.     cmp    auxfile,0        ; have override name?
  971.     jne    gofil1            ; ne = yes
  972.     cmp    flags.xflg,0        ; receiving to screen?
  973.     jne    gofil0a            ; ne = yes, filename becomes CON
  974.     cmp    flags.destflg,1        ; destination is disk?
  975.     je    gofil1            ; e = yes
  976.     mov    di,offset printer    ; assume PRN is local file name
  977.     jb    gofil0b            ; b = yes
  978. gofil0a:mov    di,offset screen    ; use CON (screen) as local file name
  979.     mov    flags.xflg,1        ; say receiving to screen
  980. gofil0b:xchg    di,si            ; di --> decbuf, si --> file name
  981.     call    strcpy            ; put local name (si) into decbuf
  982.     mov    nmoflg,1        ; say that we have a replacement name
  983.     jmp    gofil9            ; final filename is now in 'decbuf'
  984.  
  985. gofil1:    xor    ax,ax
  986.     mov    nmoflg,al        ; assume no override name
  987.     cmp    auxfile,al        ; overriding name from other side?
  988.     jne    gofi1e            ; ne = yes
  989.     jmp    gofil4            ; e = no, get the other end's filename
  990. gofi1e:    mov    nmoflg,1        ; say using an override name
  991.     mov    ax,offset auxfile    ; get local override filename
  992.     cmp    word ptr auxfile+1,003ah; colon+null?(primative drive spec A:)
  993.     je    gofil3        ; e = yes, skip screwy DOS response (No Path)
  994.     cmp    word ptr auxfile,'..'    ; parent directory?
  995.     jne    gofi1g            ; ne = no
  996.     cmp    word ptr auxfile+1,002eh ; dot dot + null?
  997.     je    gofi1b            ; e = yes, process as directory
  998. gofi1g:    cmp    word ptr auxfile,002eh    ; dot + null (current dir)?
  999.     je    gofi1b            ; e = yes, process as directory
  1000.     call    isfile            ; does it exist?
  1001.     jnc    gofi1f            ; nc = file exists
  1002.     test    filtst.fstat,80h    ; serious error?
  1003.     jz    gofil3            ; z = no, just no such file
  1004.     jmp    gofi18a            ; else quit here
  1005. gofi1f:    test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1006.     jnz    gofi1b            ; nz = yes
  1007.     cmp    filtst.fname,2eh    ; directory name?
  1008.     je    gofi1b            ; e = yes, process as directory
  1009.     cmp    auxfile+2,5ch        ; a root directory like b:\?
  1010.     jne    gofi1d            ; ne = no. (DOS is not helpful with roots)
  1011.     cmp    auxfile+3,0        ; and is it terminated in a null?
  1012.     je    gofi1b            ; e = yes, so it is a root spec
  1013. gofi1d:    test    byte ptr filtst.dta+21,0fh   ; r/o, hidden, system, vol label?
  1014.     jz    gofil3            ; z = no
  1015.      jmp    gofi18a               ; yes. Complain and don't transfer file
  1016. gofi1b:    mov    dx,offset auxfile    ; auxfile is a (sub)directory name
  1017.     call    strlen            ; get its length w/o terminator
  1018.     jcxz    gofil2            ; zero length
  1019.     dec    cx            ; examine last char
  1020.     push    bx            ; save bx
  1021.     mov    bx,cx
  1022.     add    bx,dx
  1023.     cmp    byte ptr [bx],5ch    ; ends in backslash?
  1024.     je    gofil2            ; e = yes
  1025.     cmp    byte ptr [bx],2fh    ; maybe forward slash?
  1026.     je    gofil2            ; e = yes
  1027.     mov    byte ptr [bx + 1],5ch    ; no slash yet. use backslash
  1028.     mov    byte ptr [bx + 2],0    ; plant new terminator
  1029. gofil2:    pop    bx
  1030.  
  1031. gofil3:    mov    di,offset templp    ; local path
  1032.     mov    si,offset templf    ; local filename
  1033.     mov    dx,offset auxfile    ; local string
  1034.     call    fparse            ; split local string
  1035.     mov    di,offset temprp    ; remote path
  1036.     mov    si,offset temprf    ; remote file
  1037.     mov    dx,offset decbuf    ; remote string
  1038.     mov    decbuf+64,0        ; force filename to be <= 64 chars
  1039.     call    fparse            ; split remote string
  1040.     test    flags.remflg,dserver    ; running in Server mode?
  1041.     jz    gofi3c            ; z = no
  1042.     test    denyflg,sndflg        ; is Deny Send mode in operation?
  1043.     jz    gofi3c            ; z = no
  1044.     mov    temprp,0        ; DENY, means remove remote path
  1045. gofi3c:    mov    si,offset templp    ; copy local path to
  1046.     mov    di,offset decbuf    ;  final filename
  1047.     call    strcpy            ; do the copy
  1048.     mov    si,offset templf    ; assume using local file name
  1049.     cmp    byte ptr templf,0    ; local file name given?
  1050.     jne    gofi3b            ; ne = yes
  1051.     mov    si,offset temprf    ; else use remote file name
  1052. gofi3b:    call    strcat            ; append path and filename again
  1053.                     ; offset decbuf holds the new filename
  1054.                     ;
  1055.                 ; recheck legality of filename in 'decbuf'
  1056. gofil4:    mov    decbuf+64,0        ; guard against long filenames
  1057.     mov    di,offset temprp    ; remote path
  1058.     mov    si,offset temprf    ; remote file
  1059.     mov    dx,offset decbuf    ; remote string
  1060.     call    strlen            ; get original size
  1061.     push    cx            ; remember it
  1062.     call    fparse            ; further massage filename
  1063.     push    si            ; put pieces back together
  1064.     call    verfil            ; verify each char in temprf string
  1065.     mov    si,di            ; get path part first
  1066.     mov    di,dx            ; set destination
  1067.     call    strcpy            ; copy in path part
  1068.     pop    si            ; recover (new) filename
  1069.     cmp    byte ptr [si],'.'    ; does filename part start with a dot?
  1070.     jne    gofil5            ; ne = no
  1071.     push    di            ; save regs
  1072.     push    si
  1073.     mov    di,offset rdbuf        ; a work area
  1074.     mov    byte ptr [di],'X'    ; start name with letter X
  1075.     inc    di
  1076.     call    strcpy            ; copy rest of filename
  1077.     mov    di,si
  1078.     mov    si,offset rdbuf      ; copy new name back to original location
  1079.     call    strcpy
  1080.     pop    si            ; restore regs
  1081.     pop    di    
  1082. gofil5:    call    strcat            ; append it
  1083.     call    strlen            ; see if we chopped out something
  1084.     pop    si            ; get original length (from push cx above)
  1085.     cmp    cx,si            ; same size?
  1086.     je    gofil9            ; e = yes
  1087.     mov    nmoflg,1        ; say that we have a replacement name
  1088.                 ; filename is now in 'decbuf', all converted
  1089. gofil9:    test    flags.remflg,dquiet    ; quiet display mode?
  1090.     jnz    gofi10            ; nz = yes, don't print it
  1091.     test    flags.remflg,dserial    ; serial display mode?
  1092.     jz    gofi9a            ; z = no
  1093.     mov    ah,prstr
  1094.     mov    dx,offset crlf        ; display cr/lf
  1095.     int    dos
  1096. gofi9a:    call    prtfn            ; show packet filename
  1097.     cmp    nmoflg,0        ; using local override name?
  1098.     je    gofil9b            ; e = no
  1099.     cmp    flags.xflg,0        ; receiving to screen? (X versus F)
  1100.     jne    gofil9b            ; ne = yes
  1101.     mov    ah,prstr
  1102.     mov    dx,offset asmsg        ; print " as "
  1103.     int    dos
  1104.     mov    dx,offset decbuf    ; plus the local filename
  1105.     call    prtasz            ; print asciiz string
  1106. gofil9b:mov    ah,flags.remflg        ; display a following cr/lf?
  1107.     and    ah,dserial        ; for serial display mode
  1108.     or    ah,flags.xflg        ; receiving to screen
  1109.     jz    gofi10            ; z = neither, no cr/lf
  1110.     mov    ah,prstr        ; finish the line with cr/lf
  1111.     mov    dx,offset crlf
  1112.     int    dos
  1113. gofi10:    mov    ax,offset decbuf    ; point to name
  1114.     cmp    flags.flwflg,1        ; overwrite existing file?
  1115.     jne    gofi10b            ; ne = no
  1116.     jmp    gofi16            ; e = yes
  1117. gofi10b:call    isfile            ; does it exist?
  1118.     mov    ax,offset decbuf    ; reload ptr in case
  1119.     jc    gofi16            ; carry set = no, just proceed
  1120.     mov    ah,open2        ; could it be a device name?
  1121.     xor    al,al            ; open readonly
  1122.     cmp    dosnum,300h        ; above DOS 2?
  1123.     jb    gofi10a            ; b = no, so no shared access
  1124.     or    al,40h            ; open for reading, deny none
  1125. gofi10a:mov    dx,offset decbuf    ; the filename
  1126.     int    dos
  1127.     jc    gofi11            ; c = cannot open so just proceed
  1128.     mov    bx,ax            ; file handle
  1129.     mov    ah,ioctl
  1130.     xor    al,al            ; 0 = get info
  1131.     int    dos
  1132.     mov    ah,close2        ; close it
  1133.     int    dos
  1134.     mov    ax,offset decbuf    ; point to filename again
  1135.     test    dl,80h            ; ISDEV bit set?
  1136.     jz    gofi11            ; z = no, not a device
  1137.     jmp    gofi16            ; device, use name as given
  1138. gofi11:    cmp    flags.flwflg,4        ; no-supersede existing file?
  1139.     jne    gofi12            ; ne = no (i.e., do a rename)
  1140.     mov    flags.cxzflg,'X'    ; say stop this file
  1141.     mov    word ptr decbuf,'UN'
  1142.     mov    decbuf+2,'L'        ; file name of NUL
  1143.     mov    decbuf+3,0        ; asciiz
  1144.     jmp    short gofi13
  1145. gofi12:    mov    ax,offset decbuf    ; point to filename again
  1146.     call    unique            ; generate unique name
  1147.     jc    gofi14            ; could not generate a unique name
  1148.     test    flags.remflg,dquiet    ; quiet display mode?
  1149.     jnz    gofi13            ; nz = yes, skip printing
  1150.     push    ax            ; save unique name again
  1151.     call    frpos            ; position cursor
  1152.     mov    ah,prstr           ; say we are renaming the file
  1153.     mov    dx,offset infms5
  1154.     int    dos
  1155.     pop    ax            ; get name back into ax again
  1156.     push    ax            ; save around these calls
  1157.     mov    dx,ax            ; print current filename
  1158.     call    prtasz            ; display filename
  1159.     pop    ax            ; pointer to name, again
  1160. gofi13:    jmp    short gofi16        ; and go handle file
  1161.  
  1162. gofi14:    mov    dx,offset ermes4
  1163.     call    ermsg
  1164.     stc                ; failure, dx has msg pointer
  1165.     ret
  1166.  
  1167. gofi16:    mov    si,ax             ; pointer to (maybe new) name
  1168.     mov    di,offset diskio.string    ; filename, used in open
  1169.     mov    dx,di            ;  for isfile and open below
  1170.     call    strcpy             ; copy name to diskio.string
  1171.     xor    ax,ax
  1172.     mov    diskio.sizehi,ax    ; original file size is unknown
  1173.     mov    diskio.sizelo,ax    ; double word
  1174.     mov    tfilsz,ax        ; set bytes received to zero
  1175.     mov    tfilsz+2,ax
  1176.     mov    ax,-1            ; get a minus one
  1177.     mov    oldkbt,ax
  1178.     mov    oldper,ax
  1179.     clc                ; finished composing filename
  1180.     ret                ; in diskio.string
  1181.                     ; Come here to formally open the file
  1182.  
  1183. gofi18a:mov    si,ax             ; pointer to local override name
  1184.     mov    di,offset diskio.string    ; filename, used in open
  1185.     call    strcpy             ; copy name to diskio.string
  1186.                     ; fall    through to gofi18
  1187. gofi18:    test    flags.remflg,dquiet    ; quiet display mode?
  1188.     jnz    gofi19            ; nz = yes, don't try printing
  1189.     mov    dx,offset erms12    ; unable to create file
  1190.     call    ermsg
  1191.     push    dx
  1192.     mov    dx,offset diskio.string    ; print offending name
  1193.     call    prtasz            ; display filename
  1194.     pop    dx
  1195. gofi19:    stc                ; failure, dx has msg pointer
  1196.     ret
  1197. gofil    endp
  1198.  
  1199. ; Open file for writing with name in diskio.string
  1200. goopen    proc    near
  1201.     mov    dx,offset diskio.string    ; filename, asiiz
  1202.     mov    diskio.handle,0        ; clear handle of previous usage
  1203.     mov    ax,dx            ; filename for isfile
  1204.     call    isfile        ; check for read-only/system/vol-label/dir
  1205.     jc    goopen1            ; c = file does not exist
  1206.     test    byte ptr filtst.dta+21,1fh    ; the no-no file attributes
  1207.     jnz    gofi18            ; nz = do not write over one of these
  1208. goopen1:test    filtst.fstat,80h    ; access problem?
  1209.     jnz    gofi18            ; nz = yes, quit here
  1210.     mov    diskio.handle,-1    ; clear handle of previous usage
  1211.     mov    ah,creat2        ; create file
  1212.     xor    cx,cx            ; 0 = attributes bits
  1213.     int    dos
  1214.     jc    goopen2            ; c = did not work, try regular open
  1215.     mov    diskio.handle,ax    ; save file handle here
  1216.     clc                ; carry clear for success
  1217.     ret
  1218. goopen2:test    byte ptr filtst.dta+21,1bh    ; r/o, hidden, volume label?
  1219.     jnz    gofi18            ; we won't touch these
  1220.     mov    ah,open2           ; open existing file (usually a device)
  1221.     mov    al,1+1            ; open for writing
  1222.     int    dos
  1223.     jc    gofi18            ; carry set means can't open
  1224.     mov    diskio.handle,ax    ; file handle
  1225.     clc                ; carry clear for success
  1226.     ret
  1227. goopen    endp
  1228.  
  1229. ; Given incoming filename in 'decbuf'.  Verify that each char is legal
  1230. ; (if not change it to an "X"), force max of three chars after a period (dot)
  1231. ; Source is at ds:si (si is changed here). [jrd]
  1232.  
  1233. VERFIL    PROC    NEAR
  1234.     push    es            ; verify each char in 'data'
  1235.     push    cx
  1236.     push    ds
  1237.     pop    es
  1238.     mov    havdot,0        ; say no dot found in name yet
  1239.     cld
  1240. verfi1:    lodsb                ; get a byte of name from si
  1241.     and    al,7fH            ; strip any eighth bit
  1242.     jz    verfi5            ; z = end of name
  1243.     cmp    al,'.'            ; a dot?
  1244.     jne    verfi2            ; ne = no
  1245.     cmp    havdot,0        ; have one dot already?
  1246.     jne    verfi3            ; ne = yes, change to X
  1247.     mov    byte ptr [si+3],0    ; forceably end filename after 3 char ext
  1248.     mov    havdot,1        ; say have a dot now
  1249.     jmp    short verfi4        ; continue
  1250. verfi2:    cmp    al,3ah            ; colon?
  1251.     je    verfi4
  1252.     cmp    al,5ch            ; backslash path separator?
  1253.     je    verfi4
  1254.     cmp    al,2fh            ; or forward slash?
  1255.     je    verfi4
  1256.     cmp    al,'0'
  1257.     jb    verfi3            ; see if it's a legal char < '0'
  1258.     cmp    al,'9'
  1259.     jbe    verfi4            ; it's between 0-9 so it's OK
  1260.     cmp    al,'A'
  1261.     jb    verfi3            ; check for a legal punctuation char
  1262.     cmp    al,'Z'
  1263.     jbe    verfi4            ; it's A-Z so it's OK
  1264.     cmp    al,'a'
  1265.     jb    verfi3            ; check for a legal punctuation char
  1266.     cmp    al,'z'
  1267.     ja    verfi3
  1268.     and    al,5FH            ; it's a-z, capitalize
  1269.     jmp    short verfi4        ; continue with no change
  1270.  
  1271. verfi3:    push    di            ; special char. Is it on the list?
  1272.     mov    di,offset spchar2    ; list of acceptable special chars
  1273.     mov    cx,spc2len
  1274.     cld
  1275.     repne    scasb            ; search string for input char
  1276.     pop    di
  1277.     je    verfi4            ; e = in table, return it
  1278.     mov    al,'X'            ; else illegal, replace with "X"
  1279.     mov    nmoflg,1        ; say we have a replacement filename
  1280. verfi4:    mov    [si-1],al        ; update name
  1281.     jmp    short verfi1        ; loop thru rest of name
  1282. verfi5:    mov    byte ptr[si-1],0    ; make sure it's null terminated
  1283.     pop    cx
  1284.     pop    es
  1285.     ret
  1286. VERFIL    ENDP
  1287.  
  1288. ; find a unique filename.
  1289. ; Enter with a pointer to a (null-terminated) filename in ax
  1290. ; Return with same pointer but with a new name (or old if failure)
  1291. ; Success = carry clear; failure = carry set
  1292. ; The idea is to pad out the main name part (8 chars) with ascii zeros and
  1293. ; then change the last chars successively to a 1, 2, etc. until
  1294. ; a unique name is found. All registers are preserved
  1295. ; Make empty main name fields start with letter X, not digit 0
  1296. unique    proc    near
  1297.     push    bx
  1298.     push    cx
  1299.     push    dx
  1300.     push    si
  1301.     push    di
  1302.     push    es
  1303.     push    ax            ; save address of source string
  1304.     mov    dx,ds            ; make es use ds segment
  1305.     mov    es,dx
  1306.     mov    dx,ax            ; point at original filename string
  1307.     mov    di,offset templp    ; place for path
  1308.     mov    si,offset templf    ; place for filename
  1309.     call    fparse            ; separate path (di) and filename (si)
  1310.     mov    dx,di            ; point at path part
  1311.     call    strlen            ; put length in cx
  1312.     mov    si,ax            ; point to original string
  1313.     add    si,cx            ; point to filename part
  1314.     mov    di,offset templf    ; destination is temporary location
  1315.     xor    cx,cx            ; a counter
  1316.     cld                ; set direction to be forward
  1317. uniq1:    lodsb                ; get a byte
  1318.     cmp    al,'.'            ; have a dot?
  1319.     je    uniq2            ; e = yes
  1320.     or    al,al            ; maybe    null at end?
  1321.     jnz    uniq3            ; nz = no, continue loop
  1322.  
  1323. uniq2:    cmp    cl,8            ; have we copied any chars before dot?
  1324.     jge    uniq3            ; ge = all 8
  1325.     mov    byte ptr [di],'0'    ; avoid clobbers; pad with 0's
  1326.     or    cl,cl            ; first char of filename?
  1327.     jnz    uniq2a            ; nz = no
  1328.     mov    byte ptr [di],'X'    ; start name with letter X, not 0
  1329. uniq2a:    inc    di            ; and count the output chars
  1330.     inc    cl            ; and this counter too
  1331.     jmp    short uniq2        ; continue until filled 8 slots
  1332. uniq3:    inc    cl            ; cl = # char in destination
  1333.     stosb                ; store the char
  1334.     or    al,al            ; null at end?
  1335.     jnz    uniq1            ; nz = no, continue copying
  1336.  
  1337.     mov    templf+7,'1'        ; put '1' in last name char
  1338.     mov    unum,1            ; start with this generation digit
  1339.  
  1340. uniq4:    mov    di,offset rdbuf        ; build a temporary full filename
  1341.     mov    si,offset templp    ; path part
  1342.     call    strcpy            ; copy that much
  1343.     mov    si,offset templf    ; get rebuilt filename part
  1344.     call    strcat            ; paste that to the end
  1345.     mov    ax,offset rdbuf        ; point to full name
  1346.     call    isfile            ; does it exist?
  1347.     jc    uniq6            ; c = no, succeed now
  1348.  
  1349.     inc    unum            ; move to next generation
  1350.     mov    di,offset templf+7    ; point to last name char
  1351.     mov    cx,7            ; max # of digits to play with
  1352.     mov    bx,10            ; divisor (16 bits)
  1353.     mov    ax,unum            ; low order part of generation #
  1354. uniq5:    xor    dx,dx            ; high order part of generation #
  1355.     div    bx            ; compute digit (unum / 10)
  1356.     add    dl,'0'            ; make remainder part printable
  1357.     mov    [di],dl            ; put into right place
  1358.     or    ax,ax            ; any more to do? (quotient nonzero)
  1359.     jz    uniq4            ; z = no, try this name
  1360.     dec    di            ; else decrement char position
  1361.     loop    uniq5            ;   and keep making a number
  1362.     stc                ; failure: set carry, keep old name
  1363.     jmp    short uniq7        ;   and exit
  1364.  
  1365. uniq6:    pop    di            ; address of original filename
  1366.     push    ax            ; save for exit clean up
  1367.     mov    si,offset rdbuf
  1368.     call    strcpy            ; copy new filename over old
  1369.     clc                ; success: clear carry flag
  1370. uniq7:    pop    ax
  1371.     pop    es
  1372.     pop    di
  1373.     pop    si
  1374.     pop    dx
  1375.     pop    cx
  1376.     pop    bx
  1377.     ret
  1378. unique    endp
  1379.     
  1380.  
  1381. ;    [jrd]
  1382. ; strlen -- computes the length, excluding the terminator, of an asciiz
  1383. ;    string. Input: ds:dx = address of the string
  1384. ;        Output: cx = the byte count
  1385. ;    All registers except cx are preserved
  1386. ;
  1387. STRLEN    PROC    NEAR
  1388.     push    di
  1389.     push    es
  1390.     push    ax
  1391.     mov    ax,ds            ; use proper segment address
  1392.     mov    es,ax
  1393.     mov    di,dx
  1394.     mov    cx,0ffffh        ; large byte count
  1395.     cld                ; set direction to be forward
  1396.     xor    al,al            ; item sought is a null
  1397.     repne    scasb            ; search for it
  1398.     add    cx,2            ; add for -1 and auto dec in scasb
  1399.     neg    cx              ; convert to count, excluding terminator
  1400.     pop    ax
  1401.     pop    es
  1402.     pop    di
  1403.     ret
  1404. STRLEN    ENDP
  1405.  
  1406. ;    [jrd]
  1407. ; strcat -- concatenates asciiz string 2 to the end of asciiz string 1
  1408. ;    offset of string 1 is expected to be in ds:di. input & output
  1409. ;    offset of string 2 is expected to be in ds:si. input only (unchanged)
  1410. ;    Preserves all registers. No error returns, returns normally via ret
  1411. ;
  1412. STRCAT    PROC    NEAR
  1413.     push    di            ; save work registers
  1414.     push    si
  1415.     push    es
  1416.     push    dx
  1417.     push    cx
  1418.     push    ax
  1419.     mov    ax,ds            ; get data segment value
  1420.     mov    es,ax            ; set es to ds for implied es:di usage
  1421.     mov    dx,di
  1422.     call    strlen        ; get length (w/o terminator) of dest string
  1423.     add    di,cx            ; address of first terminator
  1424.     mov    dx,si            ; start offset of source string
  1425.     call    strlen            ; find its length too (in cx)
  1426.     inc    cx            ; include its terminator in the count
  1427.     cld
  1428.     rep    movsb        ; copy source string to end of output string
  1429.     pop    ax
  1430.     pop    cx
  1431.     pop    dx
  1432.     pop    es
  1433.     pop    si
  1434.     pop    di
  1435.     ret
  1436. STRCAT    ENDP
  1437.  
  1438. ; strcpy -- copies asciiz string pointed to by ds:si into area pointed to by
  1439. ;    ds:di. Returns via ret. All registers are preserved
  1440. ;
  1441. STRCPY    PROC    NEAR
  1442.     mov    byte ptr [di],0        ; clear destination string
  1443.     call    strcat            ; let strcat do the real work
  1444.     ret
  1445. STRCPY    ENDP
  1446.  
  1447. ; fparse -- separate the drive:path part from the filename.ext part of an
  1448. ;    asciiz string. Characters separating parts are  \ or / or :
  1449. ;    Inputs:    asciiz input full filename string offset in ds:dx
  1450. ;        asciiz path offset in ds:di
  1451. ;        asciiz filename offset in ds:si
  1452. ;    Outputs: the above strings in the indicated spots
  1453. ;    Strategy is simple. Reverse scan input string until one of the
  1454. ;    three separators is encountered and then cleave at that point
  1455. ;    Simple filename construction restrictions added 30 Dec 1985;
  1456. ;    to wit: mainname limited to 8 chars or less,
  1457. ;    extension field limited to 3 chars or less and is found by searching
  1458. ;    for first occurence of a dot in the filename field. Thus the whole
  1459. ;    filename part is restricted to 12 (8+dot+3) chars plus a null
  1460. ;    All registers are preserved. Return is always via ret
  1461. ;    (Microsoft should have written this for DOS 2.x et seq.)
  1462.  
  1463. FPARSE    PROC    NEAR
  1464.     push    cx            ; local counter
  1465.     push    ax            ; local work area
  1466.     push    es            ; implied segment register for di
  1467.     push    di            ; offset of path part of output
  1468.     push    si            ; offset of file name part of output
  1469.     mov    ax,ds            ; get data segment value
  1470.     mov    es,ax            ; set es to ds for implied es:di usage
  1471.     mov    byte ptr [si],0        ; clear outputs
  1472.     mov    byte ptr [di],0
  1473.  
  1474.     push    si            ; save original file name address
  1475.     mov    si,dx            ; get original string address
  1476.     call    strcpy            ; copy string to original di
  1477.     call    strlen            ; find length (w/o terminator), in cx
  1478.     mov    si,di            ; address of string start
  1479.     add    si,cx
  1480.     dec    si            ; si = address of last non-null char
  1481.     jcxz    fpars5            ; if null skip the path scan
  1482.                     ; now find last path char, if any
  1483.                     ; start at the end of input string
  1484.     std                 ; set direction to be backward
  1485. fpars4:    lodsb                 ; get a byte (dec's si afterward)
  1486.     cmp    al,5ch            ; is it a backslash ('\')? 
  1487.     je    fpars6          ; e = yes
  1488.     cmp    al,2fh            ; or forward slash ('/')?
  1489.     je    fpars6          ; e = yes
  1490.     cmp    al,3ah            ; or even the drive terminator colon?
  1491.     je    fpars6            ; e = yes
  1492.     loop    fpars4             ; else keep looking until cx == 0
  1493.                       ; si is at beginning of file name
  1494. fpars5:    dec    si            ; dec for inc below
  1495. fpars6:    inc    si
  1496.     inc    si            ; si now points at first filename char
  1497.                     ; cx holds number of path chars
  1498.                     ; get original file name address (si)
  1499.     pop    di            ; and make it place to copy filename
  1500.     cld                ; reset direction to be forward
  1501.     mov    ax,si            ; ax holds filename address for awhile
  1502.     push    dx
  1503.     mov    dx,si            ; strlen wants string pointer in dx
  1504.     call    strlen            ; get length of filename part into cx
  1505.     pop    dx
  1506.     jcxz    fpar7a            ; any chars to look at? z = no
  1507. fpars7:    cmp    byte ptr [si],'.'    ; look for a dot in filename
  1508.     je    fpars8            ; e = found one
  1509.     inc    si            ; look at next filename char
  1510.     loop    fpars7            ; keep looking until cx = zero
  1511. fpar7a:    mov    si,ax            ; no dot. recover starting address
  1512.     mov    byte ptr [si+8],0    ; forcably truncate mainname to 8 char
  1513.     call    strcpy            ; copy this part to filename field
  1514.     jmp    short fparsx        ;  and exit
  1515. fpars8: mov    byte ptr [si+4],0   ; plant terminator after dot + 3 ext chars
  1516.     mov    cx,si
  1517.     sub    cx,ax        ; cx now = number of chars in mainname field
  1518.     cmp    cx,9            ; more than 8?
  1519.     jb    fpars9            ; b = no, we're safe
  1520.     mov    cx,8             ; limit ourselves to 8 chars in mainname
  1521. fpars9: push    si             ; remember address of dot and extension
  1522.     mov    si,ax            ; point to start of input filename
  1523.     rep    movsb            ; copy cx chars from si to di (output)
  1524.     mov    byte ptr [di],0        ; plant terminator where dot goes
  1525.     pop    si            ; source = dot and extension address
  1526.     call    strcat        ; append the dot & ext to the filename field
  1527. fparsx: mov    si,ax        ; recover start of filename in input string
  1528.     mov    byte ptr [si],0        ; terminate path field
  1529.     pop    si
  1530.     pop    di
  1531.     pop    es
  1532.     pop    ax
  1533.     pop    cx
  1534.     ret
  1535. FPARSE    ENDP    
  1536.  
  1537. ; Print filename in offset diskio.string.
  1538. PRTFN    PROC    NEAR
  1539.     test    flags.remflg,dquiet    ; quiet display mode?
  1540.     jnz    prtfn1            ; nz = yes, don't display filename
  1541.     push    ax            ; saves for messy clrfln routine
  1542.     push    bx
  1543.     push    dx
  1544.     call    clrfln            ; position cursor & blank out the line
  1545.     mov    dx,offset diskio.string
  1546.     call    prtasz
  1547.     pop    dx
  1548.     pop    bx
  1549.     pop    ax
  1550. prtfn1:    ret
  1551. PRTFN    ENDP
  1552.  
  1553.  
  1554. ; Print string to screen from offset ds:di for # bytes given in cx,
  1555. ; regardless of $'s.  All registers are preserved.        [jrd]
  1556.  
  1557. PRTSCR    PROC    NEAR
  1558.     jcxz    prtscr4            ; cx = zero means nothing to show
  1559.     push    ax
  1560.     push    bx
  1561.     push    dx
  1562.     mov    dx,di            ; source ptr for DOS
  1563.     cmp    flags.eofcz,0        ; end on Control-Z?
  1564.     jne    prtscr3            ; ne = yes, let DOS do it
  1565.     push    cx            ; else map Control-Z to space
  1566.     push    di
  1567.     push    es
  1568.     push    ds
  1569.     pop    es            ; data to es
  1570.     mov    al,ctlz            ; look for Control-Z
  1571.     cld                ; scan buffer es:di, cx chars worth
  1572. prtscr1:repne    scasb
  1573.     jne    prtscr2            ; ne = found no Control-Z's
  1574.     mov    byte ptr [di-1],' '    ; replace Control-Z with space
  1575.     jcxz    prtscr2            ; z = examined all chars
  1576.     jmp    short prtscr1        ; until examined everything
  1577. prtscr2:pop    es
  1578.     pop    di
  1579.     pop    cx
  1580. prtscr3:mov    bx,1            ; stdout file handle
  1581.     mov    ah,write2
  1582.     int    dos
  1583.     pop    dx
  1584.     pop    bx
  1585.     pop    ax
  1586. prtscr4:ret
  1587. PRTSCR    ENDP
  1588.  
  1589. ; Print to screen asciiz string given in ds:dx. Everything preserved. [jrd]
  1590. PRTASZ    PROC    NEAR
  1591.     push    cx
  1592.     push    di
  1593.     call    strlen            ; get length of asciiz string
  1594.     mov    di,dx            ; where prtscr looks
  1595.     call    prtscr            ; print counted string
  1596.     pop    di
  1597.     pop    cx
  1598.     ret
  1599. PRTASZ    ENDP
  1600.  
  1601. ;;; Load a translation table for file transfer
  1602. load    proc    near
  1603. ;;    mov    dx,offset loadtab    ; keyword Transfer-character-set
  1604. ;;    xor    bx,bx            ; help
  1605. ;;    mov    ah,cmkey
  1606. ;;    call    comnd
  1607. ;;    jnc    load0
  1608. ;;    ret
  1609. ;;load0:    mov    dx,offset rdbuf        ; buffer for filename
  1610. ;;    mov    word ptr rdbuf,0
  1611. ;;    mov    bx,offset loadhlp    ; help
  1612. ;;    mov    ah,cmword
  1613. ;;    call    comnd            ; get filename
  1614. ;;    jnc    load1            ; nc = success
  1615. ;;    ret                ; failure
  1616. ;;load1:    mov    ax,offset rdbuf        ; place for filename for isfile
  1617. ;;    call    isfile            ; does file exist?
  1618. ;;    jnc    load1b
  1619. ;;load1a:    mov    dx,offset infms6    ; unable to open file
  1620. ;;    mov    ah,prstr
  1621. ;;    int    dos
  1622. ;;    stc
  1623. ;;    ret                ; c = does not exist
  1624. ;;load1b:    mov    dx,ax
  1625. ;;    mov    cx,134
  1626. ;;    mov    ah,open2        ; file open
  1627. ;;    xor    al,al            ; 0 = open readonly
  1628. ;;    cmp    dosnum,300h        ; at or above DOS 2?
  1629. ;;    jb    load2            ; b = no, so no shared access
  1630. ;;    or    al,40h            ; open readonly, deny none
  1631. ;;load2:    int    dos
  1632. ;;    jc    load1a            ; if carry then error
  1633. ;;    mov    diskio.handle,ax    ; file handle
  1634. ;;                    ; read and parse lines
  1635. ;;    mov    linecnt,0        ; line counter
  1636. ;;    call    readln            ; L1, read and discard table name
  1637. ;;    jc    load5            ; c = failure
  1638. ;;    call    readln            ; L2, COMMON or LOCAL
  1639. ;;    jc    load5            ; c = failure
  1640. ;;    mov    ax,word ptr rdbuf
  1641. ;;    or    ax,2020h        ; to lower case
  1642. ;;    mov    tblptr,offset userin
  1643. ;;    cmp    ax,'oc'            ; "common"? (on the wire to local)
  1644. ;;    je    load4            ; e = yes
  1645. ;;    mov    tblptr,offset userout
  1646. ;;    cmp    ax,'ol'            ; "local"? (local to on the wire)
  1647. ;;    jne    load5            ; ne = no, fail
  1648. ;;
  1649. ;;load4:    call    readln            ; L3 name of comms line char set
  1650. ;;    jnc    load6            ; success
  1651. ;;load5:    jmp    loadx
  1652. ;;
  1653. ;;load6:    call    readln            ; L4 bytes per char in above set
  1654. ;;    jc    load5
  1655. ;;    mov    si,offset rdbuf        ; text, ah has char count
  1656. ;;    call    atoi            ; ax has value
  1657. ;;    jc    load5            ; c = no number
  1658. ;;    cmp    ax,1            ; one byte per char?
  1659. ;;    jne    load5            ; ne = no, fail here
  1660. ;;
  1661. ;;    call    readln            ; L5 chars/plane (94/96/128)
  1662. ;;    jc    load7            ; c = failure
  1663. ;;    mov    dx,offset rdbuf
  1664. ;;    call    strlen
  1665. ;;    mov    ah,cl
  1666. ;;    mov    si,offset rdbuf        ; text, ah has char count
  1667. ;;    call    atoi            ; ax has value
  1668. ;;    jc    load7            ; c = no number
  1669. ;;    cmp    ax,128            ; too many?
  1670. ;;    ja    load7            ; a = yes, fail here
  1671. ;;
  1672. ;;    call    readln            ; L6 name of local display char set
  1673. ;;    jnc    load8
  1674. ;;load7:    jmp    loadx
  1675. ;;
  1676. ;;load8:    call    readln            ; L7 bytes per char in above set
  1677. ;;    jc    load7
  1678. ;;    mov    dx,offset rdbuf
  1679. ;;    call    strlen
  1680. ;;    mov    ah,cl
  1681. ;;    mov    si,offset rdbuf        ; text, ah has char count
  1682. ;;    call    atoi            ; ax has value
  1683. ;;    jc    load7            ; c = no number
  1684. ;;    cmp    ax,1            ; one byte per char?
  1685. ;;    jne    load7            ; ne = no, fail here
  1686. ;;
  1687. ;;    call    readln            ; L8 chars/plane (94/96/128)
  1688. ;;    jc    load7            ; failure
  1689. ;;    mov    dx,offset rdbuf
  1690. ;;    call    strlen
  1691. ;;    mov    ah,cl
  1692. ;;    mov    si,offset rdbuf        ; text, ah has char count
  1693. ;;    call    atoi            ; ax has value
  1694. ;;    jc    load7            ; c = no number
  1695. ;;    cmp    ax,128            ; too many?
  1696. ;;    ja    load7            ; a = yes, fail here
  1697. ;;
  1698. ;;    call    readln            ; L9 designator of comms line set
  1699. ;;    jc    load8
  1700. ;;    call    readln            ; L10 Version of comms line set
  1701. ;;    jc    load8
  1702. ;;    call    readln            ; L11 Registration num of comms set
  1703. ;;    jc    load8
  1704. ;;    call    readln            ; L12 direction of writing
  1705. ;;    jc    load8
  1706. ;;    call    readln            ; L13 number of entries in table below
  1707. ;;    jc    load7
  1708. ;;    mov    dx,offset rdbuf
  1709. ;;    call    strlen
  1710. ;;    mov    ah,cl
  1711. ;;    mov    si,offset rdbuf        ; text, ah has char count
  1712. ;;    call    atoi            ; ax has value
  1713. ;;    jc    load7            ; c = no number
  1714. ;;    mov    xlines,ax
  1715. ;;
  1716. ;;    call    readln            ; L14 count of filler lines before
  1717. ;;    jc    load7            ;  table below
  1718. ;;    mov    dx,offset rdbuf
  1719. ;;    call    strlen            ; length to cx
  1720. ;;    mov    ah,cl
  1721. ;;    mov    si,offset rdbuf        ; text, ah has char count
  1722. ;;    call    atoi            ; ax has value
  1723. ;;    jc    load7            ; c = no number
  1724. ;;    mov    cx,ax            ; count of filler lines
  1725. ;;    jcxz    load10            ; z = none
  1726. ;;load9:    push    cx
  1727. ;;    call    readln            ; L15 et seq, filler lines
  1728. ;;    pop    cx            ; read and discard
  1729. ;;    jc    loadx
  1730. ;;    loop    load9
  1731. ;;
  1732. ;;load10:    dec    xlines            ; Translation data lines
  1733. ;;    cmp    xlines,0        ; any left?
  1734. ;;    jge    load11            ; ge = yes
  1735. ;;    jmp    loady
  1736. ;;load11:    call    readln            ; translation table line(s)
  1737. ;;    jc    loadx            ; c = failure
  1738. ;;    mov    si,offset rdbuf        ; the buffer
  1739. ;;    mov    dx,si
  1740. ;;    call    strlen            ; length to cx
  1741. ;;    mov    ah,cl            ; count for atoi
  1742. ;;    call    atoi            ; get "from" number
  1743. ;;    jc    loadx            ; failure
  1744. ;;    test    al,80h            ; referring to high bit set (GR)?
  1745. ;;    jnz    load12            ; nz = yes
  1746. ;;    jmp    loadx
  1747. ;;load12:    and    ax,not 0ff80h        ; strip bit for GR table
  1748. ;;    mov    temp,ax            ; save here
  1749. ;;    mov    dx,si
  1750. ;;    call    strlen
  1751. ;;    mov    ah,cl            ; count
  1752. ;;    call    atoi            ; get "to" number
  1753. ;;    mov    bx,tblptr        ; point at table
  1754. ;;    add    bx,temp            ; locate entry
  1755. ;;    mov    [bx],al            ; store new value
  1756. ;;    jmp    load10            ; repeat til done
  1757. ;;
  1758. ;;loadx:    mov    dx,offset badvalue    ; complain
  1759. ;;    mov    ah,prstr
  1760. ;;    int    dos
  1761. ;;    mov    ax,linecnt        ; show line number
  1762. ;;    call    decout
  1763. ;;    mov    ah,conout
  1764. ;;    mov    dl,':'
  1765. ;;    int    dos
  1766. ;;    mov    dx,offset rdbuf        ; show the line
  1767. ;;    call    prtasz
  1768. ;;loady:    mov    bx,diskio.handle
  1769. ;;    mov    ah,close2        ; close the file
  1770. ;;    int    dos
  1771.     clc
  1772.     ret
  1773. load    endp
  1774. ;;
  1775. ;;readln    proc    near
  1776. ;;    push    ax
  1777. ;;    push    bx
  1778. ;;    push    cx
  1779. ;;    push    dx
  1780. ;;    push    di
  1781. ;;    inc    linecnt            ; line counter
  1782. ;;    mov    cx,82            ; 82 bytes, including trailer
  1783. ;;    mov    temp,0            ; leading whitespace and comment flgs
  1784. ;;    mov    di,offset rdbuf        ; destination buffer
  1785. ;;    mov    bx,diskio.handle    ; file handle
  1786. ;;readln1:push    cx            ; read from file
  1787. ;;    mov    cx,1            ; read 1 char
  1788. ;;    mov    dx,di            ; place here
  1789. ;;    mov    byte ptr [di],0        ; insert terminator
  1790. ;;    mov    ah,readf2
  1791. ;;    int    dos
  1792. ;;    pop    cx
  1793. ;;    jc    readlnx            ; c = read failure
  1794. ;;    or    ax,ax            ; count of bytes read
  1795. ;;    jz    readlnx            ; z means end of file
  1796. ;;    cmp    byte ptr [di],LF    ; LF?
  1797. ;;    je    readln3            ; e = yes, ignore it
  1798. ;;    cmp    byte ptr [di],CR    ; end of line?
  1799. ;;    je    readln4            ; e = yes, exit
  1800. ;;    cmp    byte ptr [di],';'    ; start of comment?
  1801. ;;    jne    readln6            ; ne = no
  1802. ;;    mov    byte ptr temp+1,1    ; say comment has started
  1803. ;;    jmp    short readln3        ; do not store it
  1804. ;;readln6:cmp    byte ptr temp+1,0    ; seen comment semicolon yet?
  1805. ;;    jne    readln3            ; ne = yes, do not store comment
  1806. ;;    cmp    byte ptr temp,0        ; seen non-spacing char yet?
  1807. ;;    jne    readln2            ; ne = yes
  1808. ;;    cmp    byte ptr [di],' '    ; is this a space?
  1809. ;;    je    readln3            ; e = yes, skip it
  1810. ;;    cmp    byte ptr [di],TAB    ; or a tab?
  1811. ;;    je    readln3            ; e = yes, skip it
  1812. ;;    mov    byte ptr temp,1        ; say have seen non-spacing char
  1813. ;;readln2:cmp    flags.takflg,0        ; echo Take files?
  1814. ;;    je    readln2a        ; e = no
  1815. ;;    mov    ah,conout
  1816. ;;    mov    dl,byte ptr [di]
  1817. ;;    int    dos
  1818. ;;readln2a:inc    di            ; next storage cell
  1819. ;;readln3:loop    readln1            ; loop til end of line
  1820. ;;readln4:cmp    flags.takflg,0        ; echo Take files?
  1821. ;;    je    readln4a        ; e = no
  1822. ;;    mov    ah,prstr
  1823. ;;    mov    dx,offset crlf
  1824. ;;    int    dos
  1825. ;;readln4a:clc
  1826. ;;    mov    byte ptr [di],0        ; insert final terminator
  1827. ;;    jmp    short readlnx
  1828. ;;
  1829. ;;readln5:stc                ; set carry for failure to read
  1830. ;;readlnx:pop    di
  1831. ;;    pop    dx
  1832. ;;    pop    cx
  1833. ;;    pop    bx
  1834. ;;    pop    ax
  1835. ;;    ret
  1836. ;;readln    endp
  1837. code    ends 
  1838.     end
  1839.